package com.googlecode.yoohoo.io.socket.stream;

import java.util.UUID;

import org.osgi.framework.BundleContext;

import com.googlecode.yoohoo.utils.Constants;
import com.googlecode.yoohoo.utils.OsgiUtils;
import com.googlecode.yoohoo.xmppcore.protocol.parsing.IXmppParsingFactory;
import com.googlecode.yoohoo.xmppcore.protocol.stanza.Iq;
import com.googlecode.yoohoo.xmppcore.protocol.stanza.IqType;
import com.googlecode.yoohoo.xmppcore.protocol.stanza.error.BadRequest;
import com.googlecode.yoohoo.xmppcore.protocol.stream.Bind;
import com.googlecode.yoohoo.xmppcore.protocol.stream.error.InternalServerError;
import com.googlecode.yoohoo.xmppcore.stream.INegotiationContext;
import com.googlecode.yoohoo.xmppcore.utils.ErrorUtils;

public class ResourceBindingNegotiant extends AbstractStreamNegotiant {
	private String userName;
	private String hostName;
	
	public ResourceBindingNegotiant(String hostName) {
		this.hostName = hostName;
	}
	
	public void setUserName(String userName) {
		this.userName = userName;
	}
	
	@Override
	protected void doNegotiate(INegotiationContext context, String message) {
		if (userName == null)
			throw ErrorUtils.createProtocolException("Null user name", new InternalServerError());
		
		BundleContext bundleContext = ((NegotiationContext)context).getBundleContext();
		IXmppParsingFactory parsingFactory = OsgiUtils.getServiceInstance(bundleContext,
				IXmppParsingFactory.class, Constants.CONSTANT_XMPP_STREAM);
		
		Object obj = parsingFactory.parse(message);
		if (obj instanceof Iq) {
			Iq bindRequest = (Iq)obj;
			if (!"set".equals(bindRequest.getType())) {
				throw ErrorUtils.createProtocolException("Type of resource binding request must be 'set'.", new BadRequest());
			}
			
			Object bindObj = bindRequest.getObject();
			if (bindObj == null) {
				throw ErrorUtils.createProtocolException("Null bind element.", new BadRequest());
			}
			
			if (bindObj instanceof Bind) {
				Bind bind = (Bind)bindObj;
				if (bind.getJid() != null) {
					throw ErrorUtils.createProtocolException("Element 'jid' can't be here.", new BadRequest());
				}
				
				String resource = bind.getResource();
				if (resource == null) {
					resource = UUID.randomUUID().toString();
				}
				
				String jid = String.format("%s@%s/%s", hostName, userName, resource);
				
				if (nextNegotiant != null && nextNegotiant instanceof SessionEstablishmentNegotiant) {
					SessionEstablishmentNegotiant sessionEstablishmentNegotiant =
						(SessionEstablishmentNegotiant)nextNegotiant;
					sessionEstablishmentNegotiant.setJid(jid);
				}
				
				Iq bindResponse = new Iq();
				bindResponse.setId(bindRequest.getId());
				bindResponse.setType(IqType.RESULT.toString());
				bind = new Bind();
				bind.setJid(jid);
				bindResponse.setObject(bind);
				
				context.write(bindResponse.toXml());
				
				nextPhase(context);
			} else {
				throw ErrorUtils.createProtocolException("Not a resource binding request.", new BadRequest());
			}
		} else {
			throw ErrorUtils.createProtocolException("Not a resource binding request.", new BadRequest());
		}
	}
	
	@Override
	protected NegotiationPhase getPhase() {
		return NegotiationPhase.RESOURCE_BINDING;
	}

}
